/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c), 2003-2011,  Jin Chen and Alan M. MacEachren, GeoVISTA Center, Penn State University
 * Licensed under Simplified BSD License
 *
 *
 * @author: jin Chen
 * @date: Jan 26, 2005$
 * @version: 1.0
 */
package edu.psu.geovista.app.plot.ruler;

import edu.psu.geovista.app.pcp.toolkits.Math.JMath;
import edu.psu.geovista.app.plot.ruler.tick.DfTicksFactory;
import edu.psu.geovista.app.plot.ruler.tick.Tick;
import edu.psu.geovista.app.plot.ruler.tick.TicksFactory;
import epoviz.trex.common.text.JTextUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.AttributedString;

public class DfRulerUI implements RulerUI , PropertyChangeListener{
    public static final int DEFAULT_NUM_OF_SECTION = 4;
    // 
    protected  TicksFactory ticksFactory;  //a utility instance.Different ruler may need different Ticks and thus different Ticksfactory

    //data
    private int numOfSection; // a section is an interval between 2 neighboring ticks ( long or short)
    private  float[] tickValues=new float[getNumOfSection()+1];

    private Tick[] ticks;






  
    //temp on Format
    private int labelScale=JMath.LABEL_x1;  // 
    private int numOfDigit=2;
    private int ticklength=10;//this is default tick length, u can implement algorithm to set uneven tick lens
   // private int format=JMath.FORMAT_DIGIT;
    //private Format textFormat;  todo everything relate to formate need to configured by Format which contained by Ruler
    Ruler ruler;
    public static final int TICK_LABEL_OFFSET = 5; ////distance btw tick end and label edge


    public DfRulerUI(Ruler ruler) {
        this.ruler =ruler;
        setup();
    }

    protected void setup() {
             this.createSections(DEFAULT_NUM_OF_SECTION);//divide ruler into 4 sections
             //this.evenDivideRange();
        }
    public void paintComponent(Graphics g){
        //Color oldcolor = g.getColor();
        g.setColor(this.ruler.getColor() );  // 
           if(this.ruler.isShowTick() )
                drawTicks2(g);
           drawRuler(g);
       // g.setColor(oldcolor);


     }
    public  void drawRuler(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        int length = ruler.getLength();
        Point location = ruler.getLocation();
        int sx =location.x;;
        int sy =location.y;
        Stroke olds=g2d.getStroke() ;
        //stroke = new BasicStroke(1);
        g2d.setStroke(ruler.getStroke() );

        if (this.ruler.getOrient() ==Ruler.VERTICAL){
            g2d.drawLine(sx,sy,sx,sy+length );   //axis
        }
        else {
            g2d.drawLine(sx,sy,sx+length,sy );   //axis
        }

        g2d.setStroke(olds);
    }
    public  void drawTicks2(Graphics g) {
        for (int i=0;i<this.ticks.length ;i++){
            Tick tick = ticks[i];
            tick.paintComponent(g);
            float tickValue = tick.getValue();
            final Point loc = tick.getLocation();
            String stv=this.getReadableValue(tickValue,this.ruler.getFormat() );
            int distance=tick.getLength()+TICK_LABEL_OFFSET;
           // this.drawLabel((Graphics2D)g,stv,loc,distance,tick.getOrient());
            if(this.ruler.isShowLabel())
            this.drawLabel(g,tick);
        }

    }
    /**
     * temp solution. Assume the label is bound to the tick
     * @param tick
     *
     */
    public void  drawLabel(Graphics g,Tick tick){
        Graphics2D g2d = (Graphics2D)g;
        int loctype = tick.getOrient();
        float tickValue = tick.getValue();
        final Point loc = tick.getLocation();
        String stv=this.getReadableValue(tickValue,this.ruler.getFormat() );
        int distance=tick.getLength()+TICK_LABEL_OFFSET;

        AttributedString atts=new AttributedString(stv);
        Color lbc=ruler.getLabelColor();
        if(lbc!=null){
            atts.addAttribute(TextAttribute.FOREGROUND,lbc);
        }//if lbc ==null, not set, means use ruler's default color
        atts.addAttribute(TextAttribute.FONT,ruler.getLabelFont());
        TextLayout tl = JTextUtils.getAttributedTextLayout(atts,g2d);

        Rectangle2D tb = tl.getBounds();
        Dimension size=new Dimension((int)tb.getWidth() ,(int) tb.getHeight() );
        Point paintp = loc;//LabelLocator.getTextPaintOriginal(loc,distance,loctype,size);

        int drwx = paintp.x;//drawlocatoin.x
        int drawy = paintp.y;
        tl.draw(g2d, drwx , drawy);


        int w=(int) tb.getWidth() ;
        int h=(int) tb.getHeight() ;
        tick.setLabelBounds(drwx,drawy-h,w,h);// 
    }




    /*******************************************************************************************************
     *                draw label
     *******************************************************************************************************/


    /**
     *
     * @param g2d
     * @param s          text of the label
     * @param p          
     * @param distance   
     * @param loctype    
     */
    public void drawLabel(Graphics2D g2d, String s, Point p, int distance, int loctype) {
        AttributedString atts=new AttributedString(s);
        Color lbc=ruler.getLabelColor();
        if(lbc!=null){
            atts.addAttribute(TextAttribute.FOREGROUND,lbc);
        }//if lbc ==null, not set, means use ruler's default color
        atts.addAttribute(TextAttribute.FONT,ruler.getLabelFont());

        //TextLayout tl = JTextUtils.getPlainTextLayout(s,this.ruler.getLabelFont() ,g2d);
        TextLayout tl = JTextUtils.getAttributedTextLayout(atts,g2d);

        Rectangle2D tb = tl.getBounds();
        Dimension size=new Dimension((int)tb.getWidth() ,(int) tb.getHeight() );
        Point paintp = p;//LabelLocator.getTextPaintOriginal(p,distance,loctype,size);

        tl.draw(g2d, paintp.x , paintp.y);


    }




    private String getReadableValue(float tickValue, int format){

        return JMath.getReadableValue(tickValue,this.getLabelScale() ,this.getNumOfDigit() ,format);


    }

     /*******************************************************************************************************
      *                ticks
      *******************************************************************************************************/
     protected  void createTicks(int numOfTicks){
         TicksFactory ticksFactory = this.getTicksFactory();

         ticks = ticksFactory.createTick(numOfTicks);
         setupTicksLooks(ticks);
         setTicksLocAndValue();
          setNumOfSection( numOfTicks-1);

     }

    public int getTicklength() {
        return ticklength;
    }

    public void setTicklength(int ticklength) {
        this.ticklength = ticklength;
        for (int i=0;i<ticks.length ;i++){
            ticks[i].setLength(ticklength);
        }

    }

    /**
     *  
     *  
     */
    protected  void setupTicksLooks(Tick[] ticks) {
        //set loc type
        for (int i=0;i<ticks.length ;i++){
            final Tick tick = ticks[i];
            tick.setOrient(this.getTicksOrient());
            tick.setLength(getTicklength());// 
            tick.setColor(ruler.getColor());

        }

    }

    /**
     *  
     */
     public  void setTicksLocAndValue(){
        float[] ticksvalue = this.ruler.getTicksvalue();
        if(ticksvalue==null|| ticksvalue.length ==0){
           // 
            DfTicksFactory.setEvenDataTicks(this.ruler ,ticks,TicksFactory.ROUND_NO );
        }
        else{
            // 
           DfTicksFactory.setDataDrivenTicks(ruler,ticks,ticksvalue);
        }
     }
      /**
     * determine orientation of the ticks and labels
     * @return
     */
    protected int getTicksOrient() {
        int orient;
        if (this.ruler.getOrient() ==Ruler.VERTICAL){//VERTICAL ruler
            orient=SwingConstants.LEFT;// 
        }
        else{ //Horizontal ruler
            orient=SwingConstants.BOTTOM ;// 
        }
        return orient;
    }
     public TicksFactory getTicksFactory(){
        if(ticksFactory==null)
            ticksFactory= new DfTicksFactory();
        return ticksFactory;
    }
    /*******************************************************************************************************
     *                properties
     *******************************************************************************************************/


    public int getNumOfDigit() {
        return numOfDigit;
    }

    public void setNumOfDigit(int numOfDigit) {
        this.numOfDigit = numOfDigit;
    }



    public int getLabelScale() {
       // DecimalFormat
        return labelScale;
    }

    public void setLabelScale(int labelScale) {
        this.labelScale = labelScale;
    }


    /*public void setTickL(int tickL) {
        this.tickL = tickL;
    }

    public void setTickS(int tickS) {
        this.tickS = tickS;
    }*/



    public int getNumOfSection() {
        return numOfSection;
    }

    private  void setNumOfSection(int numOfSection) {
        this.numOfSection = numOfSection;
    }

    /**
     * divide ruler evenly into <numOfSection> section by creating ticks
     * @param numOfSection
     */
    public void createSections(int numOfSection) {

        int numOfTicks=numOfSection+1;
        this.createTicks(numOfTicks);
    }

    /*public int getTickS() {
        return tickS;
    }

    public int getTickL() {
        return tickL;
    }*/

    public Tick[] getTicks() {
        return ticks;
    }
    // 
    public void propertyChange(PropertyChangeEvent evt) {
        String pn = evt.getPropertyName();
        if(pn.equals(Ruler.PROPERTY_ORIENT ) ){
            setupTicksLooks(ticks);  //reset tick orients
            setTicksLocAndValue();//reset its location
        }
        else if (   pn.equals(Ruler.PROPERTY_TICKRANGE)
                 || pn.equals(Ruler.PROPERTY_LOCATION)
                 || pn.equals(Ruler.PROPERTY_LENGTH)){
            setTicksLocAndValue();
        }
        else if (pn.equals(Ruler.PROPERTY_TICKVALUES)){
            float[] ticksvalue = ruler.getTicksvalue();
            if(ticksvalue==null||ticksvalue.length ==0){
                // 
                this.createTicks(DEFAULT_NUM_OF_SECTION);
                //setTicksLocAndValue();
            }
            else {
                if(ticks!=null&&ticks.length ==ticksvalue.length ){
                    //no need recreate ticks, simply resign location and value
                    setTicksLocAndValue();
                }
                else{
                     createTicks(ticksvalue.length );
                }
            }
        }
       /* else if (pn.equals(Ruler.PROPERTY_LENGTH)){
            setTicksLocAndValue();
        }*/

    }
}

